home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / bootp / bootp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-13  |  16.8 KB  |  766 lines

  1. /*
  2.  * bootp.c --
  3.  *
  4.  */
  5.  
  6. #ifndef lint
  7. static char sccsid[] = "@(#)bootp.c    1.1 (Stanford) 1/22/86";
  8. #endif
  9.  
  10. /*
  11.  * BOOTP (bootstrap protocol) server daemon.
  12.  *
  13.  * Answers BOOTP request packets from booting client machines.
  14.  * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
  15.  */
  16.  
  17. /*
  18.  * history
  19.  * 01/22/86    Croft    created.
  20.  */
  21.  
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <sys/socket.h>
  25. #include <sys/ioctl.h>
  26. #include <sys/file.h>
  27.  
  28. #include <net/if.h>
  29. #include <netinet/in.h>
  30. #define    iaddr_t struct in_addr
  31. #include "bootp.h"
  32.  
  33. #include <signal.h>
  34. #include <stdio.h>
  35. #include <strings.h>
  36. #include <errno.h>
  37. #include <ctype.h>
  38. #include <netdb.h>
  39. #include <setjmp.h>
  40. #include <varargs.h>
  41. #include <time.h>
  42.  
  43. static int    debug;
  44. extern    int errno;
  45. static struct    sockaddr_in sin = { AF_INET };
  46. static int    s;        /* socket fd */
  47. static struct    sockaddr_in from;
  48. static int    fromlen;
  49. static u_char    buf[1024];    /* receive packet buffer */
  50. extern long    time();            /* time of day */
  51. static struct    ifreq ifreq[10]; /* holds interface configuration */
  52. static struct    ifconf ifconf;    /* int. config. ioctl block (points to ifreq) */
  53. static struct    arpreq arpreq;    /* arp request ioctl block */
  54.  
  55. /*
  56.  * Globals below are associated with the bootp database file (bootptab).
  57.  */
  58.  
  59. static char    *bootptab = "/etc/spritehosts";
  60. static char    *bootplog = "/sprite/admin/bootplog";
  61. static FILE    *fp;
  62. static int    f;
  63. static char    line[256];    /* line buffer for reading bootptab */
  64. static char    *linep;        /* pointer to 'line' */
  65. static int    linenum;    /* current ilne number in bootptab */
  66.  
  67. /* bootfile homedirectory */
  68. static char    homedir[] = "/sprite/boot";
  69. static char    defaultboot[] = "ds3100"; /* default file to boot */
  70.  
  71. #define    MHOSTS    512    /* max number of 'hosts' structs */
  72.  
  73. static struct hosts {
  74.     char    host[31];    /* host name (and suffix) */
  75.     u_char    htype;        /* hardware type */
  76.     u_char    haddr[6];    /* hardware address */
  77.     iaddr_t    iaddr;        /* internet address */
  78.     char    bootfile[32];    /* default boot file name */
  79. } hosts[MHOSTS];
  80.  
  81. static int    nhosts;        /* current number of hosts */
  82. static long    modtime;    /* last modification time of bootptab */
  83.  
  84. static struct in_addr myAddr;
  85.  
  86. static void log();
  87. static void request();
  88. static void reply();
  89. static void sendreply();
  90. static int nmatch();
  91. static void setarp();
  92. static void getfield();
  93. static void readtab();
  94.  
  95. unsigned char ginger[4] = {128,32,150,28};
  96.  
  97. void
  98. main(argc, argv)
  99.     char *argv[];
  100. {
  101.     register struct bootp *bp;
  102.     register int n;
  103.     char hostname[100];
  104.     struct hostent *hostentPtr;
  105.  
  106.     if (gethostname(hostname, 100) < 0) {
  107.         perror("gethostname");
  108.         exit(1);
  109.     }
  110.  
  111.     hostentPtr = gethostbyname(hostname);
  112.     if (hostentPtr == (struct hostent *)NULL) {
  113.         perror("gethostbyname");
  114.         exit(2);
  115.     }
  116.     myAddr = *(struct in_addr *)hostentPtr->h_addr_list[0];
  117.     {
  118.         unsigned char *addrPtr;
  119.  
  120.         addrPtr = (unsigned char *)&myAddr;
  121.         log("My name and addr: %s %d:%d:%d:%d\n", hostname,
  122.                 addrPtr[0], addrPtr[1], addrPtr[2], addrPtr[3]);
  123.     }
  124.  
  125.     for (argc--, argv++ ; argc > 0 ; argc--, argv++) {
  126.         if (argv[0][0] == '-') {
  127.             switch (argv[0][1]) {
  128.             case 'd':
  129.                 debug++;
  130.                 break;
  131.             }
  132.         }
  133.     }
  134.     
  135.     if (debug == 0) {
  136.         int t;
  137.         if (fork())
  138.             exit(0);
  139.         for (f = 0; f < 10; f++)
  140.             (void) close(f);
  141.         (void) open("/", 0);
  142.         (void) dup2(0, 1);
  143.         (void) dup2(0, 2);
  144.         t = open("/dev/tty", 2);    
  145.         if (t >= 0) {
  146.             ioctl(t, TIOCNOTTY, (char *)0);
  147.             (void) close(t);
  148.         }
  149.     }
  150.  
  151.     log("BOOTP server starting up.");
  152.  
  153. reopenSocket:
  154.  
  155.     while ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  156.         log("socket call failed");
  157.         sleep(5);
  158.     }
  159. #ifdef notdef
  160.     ifconf.ifc_len = sizeof ifreq;
  161.     ifconf.ifc_req = ifreq;
  162.     if (ioctl(s, SIOCGIFCONF, (caddr_t)&ifconf) < 0
  163.         || ifconf.ifc_len <= 0) {
  164.         log("'get interface config' ioctl failed");
  165.         exit(1);
  166.     }
  167. #endif
  168.     sin.sin_port = htons(IPPORT_BOOTPS);
  169.     while (bind(s, (caddr_t)&sin, sizeof (sin), 0) < 0) {
  170.         perror("bind");
  171.         log("bind call failed");
  172.         sleep(5);
  173.     }
  174.     for (;;) {
  175.         fromlen = sizeof (from);
  176.         n = recvfrom(s, buf, sizeof buf, 0, (caddr_t)&from, &fromlen);
  177.         if (n <= 0) {
  178.             log("recvfrom failed: %s\n", strerror(errno));
  179.             if (errno==ESTALE || errno==EIO) {
  180.             close(s);
  181.             log("restarting socket");
  182.             goto reopenSocket;
  183.             }
  184.             sleep(10);
  185.             continue;
  186.         }
  187.         bp = (struct bootp *) buf;
  188.         if (n < sizeof *bp) {
  189.             continue;
  190.         }
  191.         readtab();    /* (re)read bootptab */
  192.         switch (bp->bp_op) {
  193.         case BOOTREQUEST:
  194.             request();
  195.             break;
  196.  
  197.         case BOOTREPLY:
  198.             reply();
  199.             break;
  200.         }
  201.     }
  202. }
  203.  
  204.  
  205. /*
  206.  * Process BOOTREQUEST packet.
  207.  *
  208.  * (Note, this version of the bootp.c server never forwards 
  209.  * the request to another server.  In our environment the 
  210.  * stand-alone gateways perform that function.)
  211.  *
  212.  * (Also this version does not interpret the hostname field of
  213.  * the request packet;  it COULD do a name->address lookup and
  214.  * forward the request there.)
  215.  */
  216. static void
  217. request()
  218. {
  219.     register struct bootp *rq = (struct bootp *)buf;
  220.     struct bootp rp;
  221.     char *strPtr;
  222.     char path[64], file[64];
  223.     register struct hosts *hp;
  224.     register n;
  225.  
  226.     rp = *rq;    /* copy request into reply */
  227.     rp.bp_op = BOOTREPLY;
  228.     if (rq->bp_ciaddr.s_addr == 0) { 
  229.         /*
  230.          * client doesnt know his IP address, 
  231.          * search by hardware address.
  232.          */
  233.         for (hp = &hosts[0], n = 0 ; n < nhosts ; n++,hp++)
  234.             if (rq->bp_htype == hp->htype
  235.                && bcmp(rq->bp_chaddr, hp->haddr, 6) == 0)
  236.                 break;
  237.         if (n == nhosts)
  238.             return;    /* not found */
  239.         rp.bp_yiaddr = hp->iaddr;
  240.     } else {
  241.         /* search by IP address */
  242.         for (hp = &hosts[0], n = 0 ; n < nhosts ; n++,hp++)
  243.             if (rq->bp_ciaddr.s_addr == hp->iaddr.s_addr)
  244.                 break;
  245.         if (n == nhosts)
  246.             return;
  247.     }
  248.     if (strcmp(rq->bp_file, "sunboot14") == 0)
  249.         rq->bp_file[0] = 0;    /* pretend it's null */
  250.     strPtr = strchr(rq->bp_file,' ');
  251.     if (strPtr != (char *)NULL) {
  252.         *strPtr = 0;
  253.     }
  254.     log("request from %s for '%s'", hp->host, rq->bp_file);
  255.     strcpy(path, homedir);
  256.     strcat(path, "/");
  257.     strcat(path, hp->bootfile);
  258.     strcat(path, ".md/");
  259.     if (rq->bp_file[0] == 0) { /* if client didnt specify file */
  260.         if (hp->bootfile[0] == 0)
  261.             strcpy(file, defaultboot);
  262.         else
  263.             strcpy(file, hp->bootfile);
  264.     } else {
  265.         /* client did specify file */
  266.  
  267.         /*
  268.          * Test for boot from ginger.
  269.          */
  270.         if (!strcmp(rq->bp_file,"/xyzzy")) {
  271.         strcpy(rp.bp_file,"/tmp/bar");
  272.         /*
  273.         strcpy(rp.bp_file,"/home/ginger/sprite/kernels/ds3100.1.075");
  274.         */
  275.         bcopy(ginger, &rp.bp_siaddr,4);
  276.         log("Ginger boot %s",rp.bp_file);
  277.         sendreply(&rp, 1);
  278.         return;
  279.         }
  280.         /*
  281.          * For now the ds5000 always returns an extra '/' at the beginning
  282.          * of the path name. 
  283.          */
  284.          if (!strcmp(hp->bootfile, "ds5000")) {
  285.          strcpy(file, &rq->bp_file[1]);
  286.          } else {
  287.         strcpy(file, rq->bp_file);
  288.          }
  289.     }
  290.     if (file[0] == '/')    /* if absolute pathname */
  291.         strcpy(path, file);
  292.     else
  293.         strcat(path, file);
  294.     /* try first to find the file with a ".host" suffix */
  295.     n = strlen(path);
  296.     strcat(path, ".");
  297.     strcat(path, hp->host);
  298.     if (access(path, R_OK) < 0) {
  299.         path[n] = 0;    /* try it without the suffix */
  300.         if (access(path, R_OK) < 0) {
  301.             if (rq->bp_file[0])  /* client wanted specific file */
  302.                 return;        /* and we didnt have it */
  303.             log("boot file %s* missing?", path);
  304.         }
  305.     }
  306.     log("replyfile %s", path);
  307.     strcpy(rp.bp_file, path);
  308.     sendreply(&rp, 0);
  309.     return;
  310. }
  311.  
  312.  
  313. /*
  314.  * Process BOOTREPLY packet (something is using us as a gateway).
  315.  */
  316. static void
  317. reply()
  318. {
  319.     struct bootp *bp = (struct bootp *)buf;
  320.  
  321.     sendreply(bp, 1);
  322.     return;
  323. }
  324.  
  325.  
  326. /*
  327.  * Send a reply packet to the client.  'forward' flag is set if we are
  328.  * not the originator of this reply packet.
  329.  */
  330. static void
  331. sendreply(bp, forward)
  332.     register struct bootp *bp;
  333. {
  334.     iaddr_t dst;
  335.     struct sockaddr_in to;
  336.  
  337.     to = sin;
  338.     to.sin_port = htons(IPPORT_BOOTPC);
  339.     /*
  340.      * If the client IP address is specified, use that
  341.      * else if gateway IP address is specified, use that
  342.      * else make a temporary arp cache entry for the client's NEW 
  343.      * IP/hardware address and use that.
  344.      */
  345.     if (bp->bp_ciaddr.s_addr) {
  346.         dst = bp->bp_ciaddr;
  347.         if (debug) log("reply ciaddr");
  348.     } else if (bp->bp_giaddr.s_addr && forward == 0) {
  349.         dst = bp->bp_giaddr;
  350.         to.sin_port = htons(IPPORT_BOOTPS);
  351.         if (debug) log("reply giaddr");
  352.     } else {
  353.         dst = bp->bp_yiaddr;
  354.         if (debug) log("reply yiaddr %x", dst.s_addr);
  355.         setarp(&dst, bp->bp_chaddr, bp->bp_hlen);
  356.     }
  357.  
  358.     if (forward == 0) {
  359.         /*
  360.          * If we are originating this reply, we
  361.          * need to find our own interface address to
  362.          * put in the bp_siaddr field of the reply.
  363.          * If this server is multi-homed, pick the
  364.          * 'best' interface (the one on the same net
  365.          * as the client).
  366.          */
  367.         int maxmatch = 0;
  368.         int len, m;
  369.         register struct ifreq *ifrp, *ifrmax;
  370.  
  371. #ifdef notdef
  372.         ifrmax = ifrp = &ifreq[0];
  373.         len = ifconf.ifc_len;
  374.         for ( ; len > 0 ; len -= sizeof ifreq[0], ifrp++) {
  375.             if ((m = nmatch((caddr_t)&dst,
  376.                 (caddr_t)&((struct sockaddr_in *)
  377.                  (&ifrp->ifr_addr))->sin_addr)) > maxmatch) {
  378.                 maxmatch = m;
  379.                 ifrmax = ifrp;
  380.             }
  381.         }
  382.         if (bp->bp_giaddr.s_addr == 0) {
  383.             if (maxmatch == 0) {
  384.                 log("missing gateway address");
  385.                 return;
  386.             }
  387.             bp->bp_giaddr = ((struct sockaddr_in *)
  388.                 (&ifrmax->ifr_addr))->sin_addr;
  389.         }
  390. #endif
  391.         bp->bp_siaddr = myAddr;
  392.     }
  393.     to.sin_addr = dst;
  394.     if (sendto(s, (caddr_t)bp, sizeof *bp, 0, &to, sizeof to) < 0)
  395.         log("send failed");
  396.     return;
  397. }
  398.  
  399.  
  400. /*
  401.  * Return the number of leading bytes matching in the
  402.  * internet addresses supplied.
  403.  */
  404. static int
  405. nmatch(ca,cb)
  406.     register char *ca, *cb;
  407. {
  408.     register n,m;
  409.  
  410.     for (m = n = 0 ; n < 4 ; n++) {
  411.         if (*ca++ != *cb++)
  412.             return(m);
  413.         m++;
  414.     }
  415.     return(m);
  416. }
  417.  
  418.  
  419. /*
  420.  * Setup the arp cache so that IP address 'ia' will be temporarily
  421.  * bound to hardware address 'ha' of length 'len'.
  422.  */
  423. static void
  424. setarp(ia, ha, len)
  425.     iaddr_t *ia;
  426.     u_char *ha;
  427. {
  428. #ifdef notdef
  429.     struct sockaddr_in *si;
  430.  
  431.     arpreq.arp_pa.sa_family = AF_INET;
  432.     si = (struct sockaddr_in *)&arpreq.arp_pa;
  433.     si->sin_addr = *ia;
  434.     bcopy(ha, arpreq.arp_ha.sa_data, len);
  435.     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0)
  436.         log("set arp ioctl failed");
  437. #endif
  438.     return;
  439. }
  440.  
  441. static void
  442. readtab()
  443. {
  444.     struct stat st;
  445.     register char *cp;
  446.     int v;
  447.     register i;
  448.     char temp[64], tempcpy[64];
  449.     register struct hosts *hp;
  450.     char spriteID[8];
  451.     char netType[20];
  452.  
  453.     if (fp == NULL) {
  454.     if ((fp = fopen(bootptab, "r")) == NULL) {
  455.             log("can't open %s", bootptab);
  456.         exit(1);
  457.     }
  458.     }
  459.     fstat(fileno(fp), &st);
  460.     if (st.st_mtime == modtime && st.st_nlink) {
  461.     return;    /* hasnt been modified or deleted yet */
  462.     }
  463.     fclose(fp);
  464.     if ((fp = fopen(bootptab, "r")) == NULL) {
  465.     log("can't open %s", bootptab);
  466.     exit(1);
  467.     }
  468.     fstat(fileno(fp), &st);
  469.     log("(re)reading %s", bootptab);
  470.     modtime = st.st_mtime;
  471.     nhosts = 0;
  472.     hp = &hosts[0];
  473.     linenum = 0;
  474.  
  475.     /*
  476.      * read and parse each line in the file.
  477.      */
  478.     for (;;) {
  479.     if (fgets(line, sizeof line, fp) == NULL) {
  480.         break;    /* done */
  481.     }
  482.     if ((i = strlen(line))) {
  483.         line[i-1] = 0;    /* remove trailing newline */
  484.     }
  485.     linep = line;
  486.     linenum++;
  487.     /* skip leading whitespace */
  488.     while (isspace(*linep)) {
  489.         ++linep;
  490.     }
  491.     if (*linep == '#' || *linep == '\0') {
  492.         continue;    /* skip comment lines */
  493.     }
  494.     /* fill in host table */
  495.     /* get spriteid */
  496.     getfield(spriteID, sizeof(spriteID));
  497.     if (!isdigit(*spriteID)) {
  498.         log("bad sprite ID at line %d of %s", linenum, bootptab);
  499.         exit(1);
  500.     }
  501.     getfield(netType, sizeof(netType));
  502.     if (debug && strcmp(netType, "ether") && strcmp(netType, "inet")) {
  503.         log("unrecognized network type: %s, line %d, %s\n",
  504.         netType, linenum, bootptab);
  505.     }
  506.     hp->htype = 1;
  507.     getfield(temp, sizeof temp);
  508.     strcpy(tempcpy, temp);
  509.     cp = tempcpy;
  510.     /* parse hardware address */
  511.     for (i = 0 ; i < sizeof hp->haddr ; i++) {
  512.         char *cpold;
  513.         char c;
  514.         cpold = cp;
  515.         while (*cp != '.' && *cp != ':' && *cp != 0) {
  516.         cp++;
  517.         }
  518.         c = *cp;    /* save original terminator */
  519.         *cp = 0;
  520.         cp++;
  521.         if (sscanf(cpold, "%x", &v) != 1) {
  522.         goto badhex;
  523.         }
  524.         hp->haddr[i] = v;
  525.         if (c == 0) {
  526.         break;
  527.         }
  528.     }
  529.     if (i != 5) {
  530. badhex:     log("bad hex address: %s, at line %d of bootptab", temp, linenum);
  531.             continue;
  532.     }
  533.     getfield(temp, sizeof temp);
  534.     if ((i = inet_addr(temp)) == -1 || i == 0) {
  535.         log("bad internet address: %s, at line %d of bootptab",
  536.         temp, linenum);
  537.         continue;
  538.     }
  539.     hp->iaddr.s_addr = i;
  540.     getfield(hp->bootfile, sizeof hp->bootfile);
  541.     if (debug &&
  542.         strcmp(hp->bootfile, "ds3100") && strcmp(hp->bootfile, "sun3") &&
  543.         strcmp(hp->bootfile, "sun4") && strcmp(hp->bootfile, "sun4c") &&
  544.         strcmp(hp->bootfile, "spur") && strcmp(hp->bootfile, "ds5000")) {
  545.           log("unrecognized machine type: %s, line %d, %s\n",
  546.           hp->bootfile, linenum, bootptab);
  547.     }
  548.     if ((strcmp(hp->bootfile, "ds3100") != 0) &&
  549.         (strcmp(hp->bootfile, "ds5000") != 0)) {
  550.         /* bootp is only used for decStations */
  551.         continue;
  552.     }
  553.     getfield(hp->host, sizeof hp->host);
  554.     if (++nhosts >= MHOSTS) {
  555.         log("'hosts' table length exceeded");
  556.         exit(1);
  557.     }
  558.     hp++;
  559.     }
  560.     return;
  561. }
  562.  
  563.  
  564. /*
  565.  * Get next field from 'line' buffer into 'str'.  'linep' is the 
  566.  * pointer to current position.
  567.  */
  568. static void
  569. getfield(str, len)
  570.     char *str;
  571. {
  572.     register char *cp = str;
  573.  
  574.     for (; *linep && (*linep == ' ' || *linep == '\t') ; linep++) {
  575.     continue;   /* skip spaces/tabs */
  576.     }
  577.     if (*linep == '\0') {
  578.     *cp = '\0';
  579.     return;
  580.     }
  581.     len--;  /* save a spot for a null */
  582.     for (; *linep && *linep != ' ' & *linep != '\t' ; linep++) {
  583.     *cp++ = *linep;
  584.     if (--len <= 0) {
  585.         *cp = '\0';
  586.         log("string truncated: %s, on line %d of bootptab",    str, linenum);
  587.         return;
  588.     }
  589.     }
  590.     *cp = '\0';
  591.     return;
  592. }
  593.  
  594. #if 0
  595. /*
  596.  * Read bootptab database file.  Avoid rereading the file if the
  597.  * write date hasnt changed since the last time we read it.
  598.  */
  599. static void
  600. readtab()
  601. {
  602.     struct stat st;
  603.     register char *cp;
  604.     int v;
  605.     register i;
  606.     char temp[64], tempcpy[64];
  607.     register struct hosts *hp;
  608.     int skiptopercent;
  609.  
  610.     if (fp == 0) {
  611.         if ((fp = fopen(bootptab, "r")) == NULL) {
  612.             log("can't open %s", bootptab);
  613.             exit(1);
  614.         }
  615.     }
  616.     fstat(fileno(fp), &st);
  617.     if (st.st_mtime == modtime && st.st_nlink)
  618.         return;    /* hasnt been modified or deleted yet */
  619.     fclose(fp);
  620.     if ((fp = fopen(bootptab, "r")) == NULL) {
  621.         log("can't open %s", bootptab);
  622.         exit(1);
  623.     }
  624.     fstat(fileno(fp), &st);
  625.     log("(re)reading %s", bootptab);
  626.     modtime = st.st_mtime;
  627.     homedir[0] = defaultboot[0] = 0;
  628.     nhosts = 0;
  629.     hp = &hosts[0];
  630.     linenum = 0;
  631.     skiptopercent = 1;
  632.  
  633.     /*
  634.      * read and parse each line in the file.
  635.      */
  636.     for (;;) {
  637.         if (fgets(line, sizeof line, fp) == NULL)
  638.             break;    /* done */
  639.         if ((i = strlen(line)))
  640.             line[i-1] = 0;    /* remove trailing newline */
  641.         linep = line;
  642.         linenum++;
  643.         if (line[0] == '#' || line[0] == 0 || line[0] == ' ')
  644.             continue;    /* skip comment lines */
  645.         /* fill in fixed leading fields */
  646.         if (homedir[0] == 0) {
  647.             getfield(homedir, sizeof homedir);
  648.             continue;
  649.         }
  650.         if (defaultboot[0] == 0) {
  651.             getfield(defaultboot, sizeof defaultboot);
  652.             continue;
  653.         }
  654.         if (skiptopercent) {    /* allow for future leading fields */
  655.             if (line[0] != '%')
  656.                 continue;
  657.             skiptopercent = 0;
  658.             continue;
  659.         }
  660.         /* fill in host table */
  661.         getfield(hp->host, sizeof hp->host);
  662.         getfield(temp, sizeof temp);
  663.         sscanf(temp, "%d", &v);
  664.         hp->htype = v;
  665.         getfield(temp, sizeof temp);
  666.         strcpy(tempcpy, temp);
  667.         cp = tempcpy;
  668.         /* parse hardware address */
  669.         for (i = 0 ; i < sizeof hp->haddr ; i++) {
  670.             char *cpold;
  671.             char c;
  672.             cpold = cp;
  673.             while (*cp != '.' && *cp != ':' && *cp != 0)
  674.                 cp++;
  675.             c = *cp;    /* save original terminator */
  676.             *cp = 0;
  677.             cp++;
  678.             if (sscanf(cpold, "%x", &v) != 1)
  679.                 goto badhex;
  680.             hp->haddr[i] = v;
  681.             if (c == 0)
  682.                 break;
  683.         }
  684.         if (hp->htype == 1 && i != 5) {
  685.     badhex:        log("bad hex address: %s, at line %d of bootptab",
  686.                 temp, linenum);
  687.             continue;
  688.         }
  689.         getfield(temp, sizeof temp);
  690.         if ((i = inet_addr(temp)) == -1 || i == 0) {
  691.             log("bad internet address: %s, at line %d of bootptab",
  692.                 temp, linenum);
  693.             continue;
  694.         }
  695.         hp->iaddr.s_addr = i;
  696.         getfield(hp->bootfile, sizeof hp->bootfile);
  697.         if (++nhosts >= MHOSTS) {
  698.             log("'hosts' table length exceeded");
  699.             exit(1);
  700.         }
  701.         hp++;
  702.     }
  703.     return;
  704. }
  705.  
  706.  
  707. /*
  708.  * Get next field from 'line' buffer into 'str'.  'linep' is the 
  709.  * pointer to current position.
  710.  */
  711. static void
  712. getfield(str, len)
  713.     char *str;
  714. {
  715.     register char *cp = str;
  716.  
  717.     for ( ; *linep && (*linep == ' ' || *linep == '\t') ; linep++)
  718.         ;    /* skip spaces/tabs */
  719.     if (*linep == 0) {
  720.         *cp = 0;
  721.         return;
  722.     }
  723.     len--;    /* save a spot for a null */
  724.     for ( ; *linep && *linep != ' ' & *linep != '\t' ; linep++) {
  725.         *cp++ = *linep;
  726.         if (--len <= 0) {
  727.             *cp = 0;
  728.             log("string truncated: %s, on line %d of bootptab",
  729.                 str, linenum);
  730.             return;
  731.         }
  732.     }
  733.     *cp = 0;
  734.     return;
  735. }
  736. #endif
  737.  
  738. /*
  739.  * log an error message 
  740.  *
  741.  */
  742. static void
  743. log(va_alist)
  744.     va_dcl
  745. {
  746.     FILE *fp;
  747.     char *format;
  748.     va_list args;
  749.     time_t now;
  750.     char *t;
  751.  
  752.     va_start(args);
  753.     time(&now);
  754.     t = asctime(localtime(&now));
  755.     /* remove the newline */
  756.     t[24] = '\0';
  757.     if ((fp = fopen(bootplog, "a+")) == NULL)
  758.         return;
  759.     fprintf(fp, "[%s]: ", t);
  760.     format = va_arg(args, char *);
  761.     vfprintf(fp, format, args);
  762.     putc('\n', fp);
  763.     fclose(fp);
  764.     return;
  765. }
  766.